package com.infolab.aims.service;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Join;
import javax.persistence.criteria.JoinType;
import javax.persistence.criteria.ParameterExpression;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.infolab.aims.GlobalConstant;
import com.infolab.aims.common.InQueryHelper;
import com.infolab.aims.common.NotEqualQueryHelper;
import com.infolab.aims.common.PaginationHelper;
import com.infolab.aims.common.QueryHelper;
import com.infolab.aims.common.bean.SearchCriteria;
import com.infolab.aims.common.bean.SearchResult;
import com.infolab.aims.domain.Location;
import com.infolab.aims.domain.SystemCodeType;
import com.infolab.aims.domain.SystemUser;
import com.infolab.aims.domain.Vehicle;
import com.infolab.aims.domain.asset.AssetEquipment;
import com.infolab.aims.domain.asset.AssetEquipmentPK;
import com.infolab.aims.domain.asset.AssetModel;
import com.infolab.aims.domain.asset.AssetTransaction;
import com.infolab.aims.domain.asset.AssetTransactionItem;
import com.infolab.aims.domain.workorder.WorkOrder;
import com.infolab.aims.domain.workorder.WorkOrderAdHoc;
import com.infolab.aims.domain.workorder.WorkOrderDetail;
import com.infolab.aims.domain.workorder.WorkOrderPart;
import com.infolab.aims.domain.workorder.WorkOrderTechnician;
import com.infolab.aims.service.intf.AssetModelService;
import com.infolab.aims.service.intf.AssetTransactionService;
import com.infolab.aims.service.intf.VehicleService;
import com.infolab.aims.service.intf.WorkOrderAdHocService;
import com.infolab.aims.service.intf.WorkOrderServiceFacade;
import com.infolab.scheduler.domain.IntfDriver;
import com.infolab.scheduler.domain.IntfPartReplacement;
import com.infolab.scheduler.domain.IntfTaxiDowntime;


@Service
@Transactional
public class WorkOrderServiceFacadeImpl implements WorkOrderServiceFacade {

	Log logger = LogFactory.getLog(getClass());
	@PersistenceContext
	private EntityManager em;

	@Autowired
	private VehicleService vehicleService;
	
	@Autowired
	private AssetModelService assetModelService;

	@Autowired
	private WorkOrderAdHocService workOrderAdHocService;
	
	@Autowired
	private AssetTransactionService assetTransactionService;

	public void createWorkOrder(WorkOrder workOrder)
	{

		WorkOrder newWorkOrder = new WorkOrder();

		String workOrderCode = new SimpleDateFormat("yyyy/MM/dd").format(new Date())+"/";

		Integer nextVal = (Integer) em.createNativeQuery("select nextval('AMSQ_CT_WORKORDER') from dual").getSingleResult();

		workOrderCode = workOrderCode+String.format("%04d", nextVal.intValue());
		
		logger.info("Generated work order " + workOrderCode);

		
		workOrder.setWorkOrderCode(workOrderCode);

		workOrder.setDateBooking(new Date());

		workOrder.setDateCreated(new Date());
		
		workOrder.setDateModified(new Date());
		
		workOrder.setModifiedBy(workOrder.getCreatedBy());

		workOrder.setWorkOrderStatus(WorkOrder.WORKORDERSTATUS_INQUEUE);

		BeanUtils.copyProperties(workOrder,newWorkOrder);

		em.persist(newWorkOrder);

		workOrder.setWorkOrderId(newWorkOrder.getWorkOrderId());

		updateWorkOrderAdHocs(workOrder);

		updateWorkOrderComplaints(workOrder);

//		Vehicle vehicle = vehicleService.getVehicle(workOrder.getVehicleId());
//		
//		List<VehiclePart> vehicleParts = vehicle.getVehicleParts();
		
		SearchCriteria searchCriteria = new SearchCriteria();
		searchCriteria.addSearchCriteria("subLocationId", workOrder.getVehicleId());
		List<AssetEquipment> assetEquipments = assetModelService.findAssetEquipments(searchCriteria);
		if(assetEquipments!=null)
		{
			for(int i=0;i<assetEquipments.size();i++)
			{
				AssetEquipment assetEquipment = assetEquipments.get(i);
				WorkOrderPart workOrderPart = new WorkOrderPart();
				workOrderPart.setWorkOrder(workOrder);
				workOrderPart.setOldSerialNo(assetEquipment.getAssetEquipmentPK().getSerialNo());
				workOrderPart.setAssetModel(assetEquipment.getAssetEquipmentPK().getAssetModel());
				em.persist(workOrderPart);	
			}
		}


	}


	private void updateWorkOrderAdHocs(WorkOrder workOrder) {
		if(workOrder.getWorkOrderAdHocs()!=null)
		{
			List<WorkOrderAdHoc> workOrderAdHocs = workOrder.getWorkOrderAdHocs();
			for(int i=0;i<workOrderAdHocs.size();i++)
			{
				WorkOrderAdHoc workOrderAdHoc = workOrderAdHocs.get(i);
				if(workOrderAdHoc.isAdHocStatusCompleted())
				{
					workOrderAdHoc = em.getReference(WorkOrderAdHoc.class, workOrderAdHoc.getWorkOrderAdHocId());
					workOrderAdHoc.setAdHocStatus(WorkOrderAdHoc.ADHOCSTATUS_COMPLETED);
					workOrderAdHoc.setWorkOrder(workOrder);
					em.merge(workOrderAdHoc);	
				}
				else
				{

					workOrderAdHoc = em.getReference(WorkOrderAdHoc.class, workOrderAdHoc.getWorkOrderAdHocId());
					workOrderAdHoc.setAdHocStatus(WorkOrderAdHoc.ADHOCSTATUS_NEW);
					workOrderAdHoc.setWorkOrder(null);
					em.merge(workOrderAdHoc);
				}

			}
		}
	}

	private void updateWorkOrderComplaints(WorkOrder workOrder) {
		if(workOrder.getWorkOrderComplaints()!=null)
		{
			List<WorkOrderDetail> workOrderDetails = workOrder.getWorkOrderComplaints();
			for(int i=0;i<workOrderDetails.size();i++)
			{

				WorkOrderDetail workOrderDetail = workOrderDetails.get(i);
				if(workOrderDetail.getWorkOrder()==null)
				{

				}
				else if(workOrderDetail.isDeleted())
				{
					workOrderDetail = em.getReference(WorkOrderDetail.class, workOrderDetail.getWorkOrderDetailId());
					em.remove(workOrderDetail);
				}
				else if(workOrderDetail.getWorkOrderDetailId()!=null)
				{
					if(workOrderDetail.getGenericCode().getSystemCodeValueId()==null)
						workOrderDetail.setGenericCode(null);

					workOrderDetail.setWorkOrder(workOrder);
					workOrderDetail.setWorkOrderDetailType(WorkOrderDetail.WORKORDERDETAILTYPE_COMPLAINT);
					em.merge(workOrderDetail);
				}
				else
				{
					if(workOrderDetail.getGenericCode().getSystemCodeValueId()==null)
						workOrderDetail.setGenericCode(null);
					workOrderDetail.setWorkOrder(workOrder);
					workOrderDetail.setWorkOrderDetailType(WorkOrderDetail.WORKORDERDETAILTYPE_COMPLAINT);
					em.persist(workOrderDetail);
				}
			}
		}
	}

	private void updateWorkOrderRepairs(WorkOrder workOrder) {
		if(workOrder.getWorkOrderRepairs()!=null)
		{
			List<WorkOrderDetail> workOrderDetails = workOrder.getWorkOrderRepairs();
			for(int i=0;i<workOrderDetails.size();i++)
			{
				WorkOrderDetail workOrderDetail = workOrderDetails.get(i);
				if(workOrderDetail.getWorkOrder()==null || workOrderDetail.getGenericCode().getSystemCodeValueId()==null)
				{

				}
				else if(workOrderDetail.isDeleted())
				{
					workOrderDetail = em.getReference(WorkOrderDetail.class, workOrderDetail.getWorkOrderDetailId());
					em.remove(workOrderDetail);
				}
				else if(workOrderDetail.getWorkOrderDetailId()!=null)
				{
					workOrderDetail.setWorkOrder(workOrder);
					workOrderDetail.setWorkOrderDetailType(WorkOrderDetail.WORKORDERDETAILTYPE_REPAIR);
					em.merge(workOrderDetail);
				}
				else
				{
					workOrderDetail.setWorkOrder(workOrder);
					workOrderDetail.setWorkOrderDetailType(WorkOrderDetail.WORKORDERDETAILTYPE_REPAIR);
					em.persist(workOrderDetail);
				}
			}
		}
	}

	private void updateWorkOrderParts(WorkOrder workOrder) {
		if(workOrder.getWorkOrderParts()!=null)
		{
			List<WorkOrderPart> workOrderParts = workOrder.getWorkOrderParts();
			for(int i=0;i<workOrderParts.size();i++)
			{
				WorkOrderPart workOrderPart = workOrderParts.get(i);
				if(workOrderPart.getWorkOrder()==null)
				{

				}
				else if(workOrderPart.isDeleted())
				{
					workOrderPart = em.getReference(WorkOrderPart.class, workOrderPart.getWorkOrderPartId());
					em.remove(workOrderPart);
				}
				else if(workOrderPart.getWorkOrderPartId()!=null)
				{
					workOrderPart.setWorkOrder(workOrder);

					em.merge(workOrderPart);
				}
				else
				{
					workOrderPart.setWorkOrder(workOrder);

					em.persist(workOrderPart);
				}
			}
		}
	}

	public void updateWorkOrder(WorkOrder workOrder) {

		//		if(workOrder.getSection()==null || workOrder.getSection().getSectionId()==null)
		//			workOrder.setSection(null);

		WorkOrder newWorkOrder = em.find(WorkOrder.class, workOrder.getWorkOrderId());

		newWorkOrder.setModifiedBy(workOrder.getModifiedBy());
		newWorkOrder.setDateModified(new Date());
		//BeanUtils.copyProperties(workOrder,newWorkOrder);

		newWorkOrder.setDriverEmail(workOrder.getDriverEmail());
		newWorkOrder.setDriverName(workOrder.getDriverName());
		newWorkOrder.setDriverTelephoneNo(workOrder.getDriverTelephoneNo());
		newWorkOrder.setDriverType(workOrder.getDriverType());
		newWorkOrder.setDriverNric(workOrder.getDriverNric());
		newWorkOrder.setMeVersion(workOrder.getMeVersion());
		
		newWorkOrder.setWorkOrderType(workOrder.getWorkOrderType());

		em.merge(newWorkOrder);

		updateWorkOrderAdHocs(workOrder);

		updateWorkOrderComplaints(workOrder);

		updateWorkOrderRepairs(workOrder);

		updateWorkOrderParts(workOrder);
	}


	public WorkOrder getWorkOrder(Integer workOrderId) {

		WorkOrder workOrder = em.find(WorkOrder.class, workOrderId);
		Query query = em.createQuery("from WorkOrderDetail where workOrder.workOrderId=:workOrderId and workOrderDetailType=:workOrderDetailType  order by workOrderDetailId");
		query.setParameter("workOrderId", workOrderId);
		query.setParameter("workOrderDetailType", WorkOrderDetail.WORKORDERDETAILTYPE_COMPLAINT);
		List<WorkOrderDetail> workOrderComplaints = query.getResultList();
		workOrder.setWorkOrderComplaints(workOrderComplaints);

		query = em.createQuery("from WorkOrderDetail where workOrder.workOrderId=:workOrderId and workOrderDetailType=:workOrderDetailType order by workOrderDetailId");
		query.setParameter("workOrderId", workOrderId);
		query.setParameter("workOrderDetailType", WorkOrderDetail.WORKORDERDETAILTYPE_REPAIR);
		List<WorkOrderDetail> workOrderRepairs = query.getResultList();
		workOrder.setWorkOrderRepairs(workOrderRepairs);

		query = em.createQuery("from WorkOrderPart where workOrder.workOrderId=:workOrderId  order by workOrderPartId");
		query.setParameter("workOrderId", workOrderId);
		List<WorkOrderPart> workOrderParts = query.getResultList();
		workOrder.setWorkOrderParts(workOrderParts);

		query = em.createQuery("from WorkOrderTechnician where workOrder.workOrderId=:workOrderId  order by workOrderTechnicianId");
		query.setParameter("workOrderId", workOrderId);
		List<WorkOrderTechnician> workOrderTechnicians = query.getResultList();
		workOrder.setWorkOrderTehnicians(workOrderTechnicians);


		// query ad-hoc
		if(workOrder.isWorkOrderStatusClosed())
		{
			SearchCriteria searchCriteria = new SearchCriteria();
			searchCriteria.addSearchCriteria("vehicleId", workOrder.getVehicleId());
			searchCriteria.addSearchCriteria("adHocStatus", WorkOrderAdHoc.ADHOCSTATUS_COMPLETED);
			searchCriteria.addSearchCriteria("workOrderId", workOrder.getWorkOrderId());
			List<WorkOrderAdHoc> workOrderAdHocs = workOrderAdHocService.findWorkOrderAdHocs(searchCriteria);

			workOrder.setWorkOrderAdHocs(workOrderAdHocs);
		}
		else
		{

			SearchCriteria searchCriteria = new SearchCriteria();
			searchCriteria.addSearchCriteria("vehicleId", workOrder.getVehicleId());
			searchCriteria.addSearchCriteria("adHocStatusNotCompleted", WorkOrderAdHoc.ADHOCSTATUS_COMPLETED);
			searchCriteria.addSearchCriteria("workOrderId", workOrder.getWorkOrderId());
			List<WorkOrderAdHoc> workOrderAdHocs = workOrderAdHocService.findWorkOrderAdHocs(searchCriteria);			
			workOrder.setWorkOrderAdHocs(workOrderAdHocs);
		}

		return workOrder;
	}
	
	public WorkOrderTechnician getWorkOrderTechnician(Integer workOrderTechnicianId) {
		WorkOrderTechnician workOrderTechnician = em.find(WorkOrderTechnician.class, workOrderTechnicianId);		
		return workOrderTechnician;
	}

	public WorkOrder findWorkOrder(SearchCriteria searchCriteria) {
		searchCriteria.setMaxRow(1);
		List<WorkOrder> workOrders  = findWorkOrders(searchCriteria);
		if(workOrders!=null && workOrders.size()>=1)
			return workOrders.get(0);

		return null;
	}

	public List<WorkOrder> findWorkOrders(SearchCriteria searchCriteria) {

		CriteriaBuilder cb = em.getCriteriaBuilder();
		CriteriaQuery<WorkOrder> cq = cb.createQuery(WorkOrder.class);
		Root<WorkOrder> root = cq.from(WorkOrder.class);
		List<Predicate> criteria = new ArrayList<Predicate>();

		Join<WorkOrder,SystemUser> technician = null;
		if (searchCriteria.getSearchCriteria("technicianName")!= null) {
			technician =
				root.join("technician", JoinType.LEFT);	
		}

		if (searchCriteria.getSearchCriteria("workOrderCode")!= null) {
			
			ParameterExpression<String> p = cb.parameter(String.class, "workOrderCode");
			criteria.add(cb.equal(root.get("workOrderCode"),  p));
		}

		if (searchCriteria.getSearchCriteria("vehicleId")!= null) {
			ParameterExpression<String> p =
				cb.parameter(String.class, "vehicleId");
			criteria.add(cb.equal(root.get("vehicleId"), p));
		}

		if (searchCriteria.getSearchCriteria("workOrderStatus")!= null) {
			
			Object obj = searchCriteria.getSearchCriteria("workOrderStatus");
			if(obj instanceof InQueryHelper)
			{
				ParameterExpression<List> p = cb.parameter(List.class, "workOrderStatus");
				criteria.add(cb.in(root.get("workOrderStatus")).value(p));
			}
			else if(obj instanceof NotEqualQueryHelper)
			{	
				ParameterExpression<String> p =
					cb.parameter(String.class, "workOrderStatus");
				criteria.add(cb.notEqual(root.get("workOrderStatus"), p));
			}
			else
			{
				ParameterExpression<String> p =
					cb.parameter(String.class, "workOrderStatus");
				criteria.add(cb.equal(root.get("workOrderStatus"), p));
			}
		}

		if (searchCriteria.getSearchCriteria("technicianName")!= null) {
			ParameterExpression<String> p =
				cb.parameter(String.class, "technicianName");
			criteria.add(cb.like(cb.upper(technician.<String>get("personName")), cb.upper(p)));
		}

		cq.select(root);

		if (criteria.size() == 0) {
		} else if (criteria.size() == 1) {
			cq.where(criteria.get(0));
		} else {
			cq.where(cb.and(criteria.toArray(new Predicate[0])));
		}

		if(searchCriteria.getSortType()!=null)
		{
			if(searchCriteria.isAscendingSort())
				cq.orderBy(cb.asc(root.get(searchCriteria.getSortName())));
			else
				cq.orderBy(cb.desc(root.get(searchCriteria.getSortName())));	
		}

		Query query = em.createQuery(cq);

		if (searchCriteria.getSearchCriteria("workOrderCode")!= null) {
			query.setParameter("workOrderCode", searchCriteria.getSearchCriteria("workOrderCode"));
		}
		if (searchCriteria.getSearchCriteria("vehicleId")!= null) {
			query.setParameter("vehicleId", searchCriteria.getSearchCriteria("vehicleId"));
		}
		if (searchCriteria.getSearchCriteria("workOrderStatus")!= null) {
			Object obj = searchCriteria.getSearchCriteria("workOrderStatus");
			
			if(obj instanceof InQueryHelper)
				query.setParameter("workOrderStatus", ((InQueryHelper)obj).getColumnValues());
			else if(obj instanceof NotEqualQueryHelper)
				query.setParameter("workOrderStatus", ((NotEqualQueryHelper)obj).getColumnValue());
			else
				query.setParameter("workOrderStatus", searchCriteria.getSearchCriteria("workOrderStatus"));
		}
		if (searchCriteria.getSearchCriteria("technicianName")!= null) {
			query.setParameter("technicianName", "%"+searchCriteria.getSearchCriteria("technicianName")+"%");
		}

		if(searchCriteria.getMaxRow()!=null)
			query.setMaxResults(searchCriteria.getMaxRow());


		List<WorkOrder> workOrders  = query.getResultList();
		if(workOrders==null || workOrders.size()==0)
			return null;

		return workOrders;
	}

	public SearchResult searchWorkOrder(
			SearchCriteria searchCriteria) {
		
		if(searchCriteria.getCurPage()==null)
			searchCriteria.setCurPage(1);
		
		WorkOrderPaginationHelper helper = new WorkOrderPaginationHelper();

		return helper.getSearchResultFromQueryHelper(em, searchCriteria);
	}

	public void deleteWorkOrder(Integer workOrderId) {

		Query query = em.createQuery("update WorkOrder set active=0 where workOrderId=:workOrderId");

		query.setParameter("workOrderId", workOrderId);

		query.executeUpdate();

	}

	public static class WorkOrderPaginationHelper extends PaginationHelper<WorkOrder> {

		@Override
		public String[] getValidColumnName() {
			return new String[]{"workOrderCode","vehicleId","personName","workOrderStatus","dateBooking","accessDepartmentId"};
		}

		@Override
		public String[] getValidSortName() {
			return new String[]{"workOrderCode","vehicleId","personName","workOrderStatus","dateBooking","modifiedBy","dateModified"};
		}

		@Override
		public String getDefaultSortName() {
			return "workOrderCode";
		}

		@Override
		public QueryHelper getQueryHelper() {
			QueryHelper queryHelper = new QueryHelper();
			queryHelper.select("select workOrder from WorkOrder workOrder left join workorder.technician technician");
			return queryHelper;
		}
	}


	public void closeWorkOrder(WorkOrder workOrder) {

		WorkOrder currentWorkOrder  = em.find(WorkOrder.class, workOrder.getWorkOrderId());
		currentWorkOrder.setDateModified(new Date());
		
		currentWorkOrder.setModifiedBy(workOrder.getModifiedBy());
		
		currentWorkOrder.setWorkOrderStatus(WorkOrder.WORKORDERSTATUS_CLOSED);

		String vehicleId = currentWorkOrder.getVehicleId();
		String driverNric = currentWorkOrder.getDriverNric();
		String driverName = currentWorkOrder.getDriverName();
		String telephoneNo = currentWorkOrder.getDriverTelephoneNo();
		String driverEmail = currentWorkOrder.getDriverEmail();
		String driverType = currentWorkOrder.getDriverType();
		String meVersion = currentWorkOrder.getMeVersion();
		String companyCode  = currentWorkOrder.getCompanyCode();
		String assetModelCode  = currentWorkOrder.getAssetModelCode();

		SearchCriteria searchCriteria = new SearchCriteria();
		searchCriteria.addSearchCriteria("nric", driverNric);

		Vehicle vehicle = new Vehicle();
		vehicle.setVehicleId(vehicleId);
		vehicle.setDriverNric(driverNric);
		vehicle.setDriverName(driverName);
		vehicle.setDriverTelephoneNo(telephoneNo);
		vehicle.setDriverEmail(driverEmail);
		vehicle.setDriverType(driverType);
		vehicle.setMeVersion(meVersion);
		//vehicleService.updateVehicle(vehicle);

		Query query = em.createQuery("from WorkOrderPart where workOrder.workOrderId=:workOrderId  order by workOrderPartId");
		query.setParameter("workOrderId",  workOrder.getWorkOrderId());
		List<WorkOrderPart> workOrderParts = query.getResultList();

		vehicle = vehicleService.getVehicle(vehicleId);
		//List<VehiclePart> vehicleParts = new ArrayList<VehiclePart>();
		
		
		Location newSerialNoLocation = getLocationForNewSerialNo();
		Location oldSerialNoLocation = getLocationForOldSerialNo();
		
		searchCriteria = new SearchCriteria();
		searchCriteria.addSearchCriteria("subLocationId", workOrder.getVehicleId());
		List<AssetEquipment> assetEquipments = assetModelService.findAssetEquipments(searchCriteria);
		if(assetEquipments!=null)
		{
			for(int i=0;i<assetEquipments.size();i++)
			{
				AssetEquipment assetEquipment = assetEquipments.get(i);
				
				boolean foundSerial=false;
				if(workOrderParts!=null && workOrderParts.size()!=0)
				{
					for(int j=0;j<workOrderParts.size();j++)
					{
						WorkOrderPart workOrderPart = workOrderParts.get(j);
						if(StringUtils.equalsIgnoreCase(assetEquipment.getAssetEquipmentPK().getSerialNo(), workOrderPart.getOldSerialNo()))
						{
							foundSerial=true;
							break;
						}
					}
				}
				
				if(!foundSerial)
				{
					//if old serial no changes, old serial no should update back to service centre with status active
					logger.info("Old serial no changes  : " + assetEquipment.getAssetEquipmentPK().getSerialNo());
					
					Location prevLocation = assetEquipment.getLocation();
					assetEquipment.setLocation(oldSerialNoLocation);
					assetEquipment.setSubLocationId(null);
					assetEquipment.setAssetEquipmentStatus(AssetModel.ASSETSTATUS_ACTIVE);
					em.merge(assetEquipment);
					
					if(prevLocation.getLocationId().intValue()!=oldSerialNoLocation.getLocationId().intValue())
						createAssetTransactionfromPartChanges(currentWorkOrder, assetEquipment,prevLocation , oldSerialNoLocation);
					//TODO: this serial no should be inserted into asset transaction moving from in vehicle to service centre
				}
			}
		}
		
		if(workOrderParts!=null && workOrderParts.size()!=0)
		{
			for(int i=0;i<workOrderParts.size();i++)
			{
				WorkOrderPart workOrderPart = workOrderParts.get(i);
				AssetModel assetModel = workOrderPart.getAssetModel();

				String oldSerialNo = workOrderPart.getOldSerialNo();
				String newSerialNo = workOrderPart.getNewSerialNo();
//				VehiclePart vehiclePart = new VehiclePart();
//				vehiclePart.setVehicle(vehicle);
//				if(StringUtils.isNotEmpty(newSerialNo))
//					vehiclePart.setVehiclePartPK(new VehiclePartPK(assetModel,newSerialNo));
//				else if(StringUtils.isNotEmpty(oldSerialNo))
//					vehiclePart.setVehiclePartPK(new VehiclePartPK(assetModel,oldSerialNo));
//				vehicleParts.add(vehiclePart);


				if(StringUtils.isNotEmpty(newSerialNo)) // update new serial no to in vehicle
				{
					AssetEquipmentPK assetEquipmentPK = new AssetEquipmentPK(assetModel,newSerialNo);
					AssetEquipment assetEquipment = em.find(AssetEquipment.class, assetEquipmentPK);
					if(assetEquipment!=null)
					{						
						Location prevLocation = assetEquipment.getLocation();
						
						assetEquipment.setLocation(newSerialNoLocation);
						assetEquipment.setSubLocationId(vehicle.getVehicleId());
						em.merge(assetEquipment);
						
						if(prevLocation.getLocationId().intValue()!=newSerialNoLocation.getLocationId().intValue())
							createAssetTransactionfromPartChanges(currentWorkOrder, assetEquipment,prevLocation , newSerialNoLocation);
					}
				}
				if(StringUtils.isNotEmpty(oldSerialNo) && StringUtils.isNotEmpty(newSerialNo)) // updating old serial no to service centre
				{
					AssetEquipmentPK assetEquipmentPK = new AssetEquipmentPK(assetModel,oldSerialNo);
					AssetEquipment assetEquipment = em.find(AssetEquipment.class, assetEquipmentPK);
					if(assetEquipment!=null)
					{
						Location prevLocation = assetEquipment.getLocation();
						
						assetEquipment.setAssetEquipmentStatus(AssetModel.ASSETSTATUS_FAULT);
						assetEquipment.setLocation(oldSerialNoLocation);
						assetEquipment.setSubLocationId(null);
						em.merge(assetEquipment);
						
						if(prevLocation.getLocationId().intValue()!=oldSerialNoLocation.getLocationId().intValue())
							createAssetTransactionfromPartChanges(currentWorkOrder, assetEquipment,prevLocation , oldSerialNoLocation);
					}
				}
				else if(StringUtils.isNotEmpty(oldSerialNo) && StringUtils.isEmpty(newSerialNo))
				{
					AssetEquipmentPK assetEquipmentPK = new AssetEquipmentPK(assetModel,oldSerialNo);
					AssetEquipment assetEquipment = em.find(AssetEquipment.class, assetEquipmentPK);
					if(assetEquipment!=null)
					{
						Location prevLocation = assetEquipment.getLocation();
						
						assetEquipment.setAssetEquipmentStatus(AssetModel.ASSETSTATUS_ACTIVE);
						assetEquipment.setLocation(newSerialNoLocation);
						assetEquipment.setSubLocationId(vehicle.getVehicleId());
						em.merge(assetEquipment);
						
						if(prevLocation.getLocationId().intValue()!=newSerialNoLocation.getLocationId().intValue())
							createAssetTransactionfromPartChanges(currentWorkOrder, assetEquipment,prevLocation , newSerialNoLocation);
					}
				} 
			}
		}
		currentWorkOrder.setWorkOrderParts(workOrderParts);
		em.merge(currentWorkOrder);
		sendIntoFMSInterface(currentWorkOrder);
//		vehicle.setVehicleParts(vehicleParts);
//		em.merge(vehicle);
	}
	
	
	private void sendIntoFMSInterface(WorkOrder workOrder)
	{
		IntfDriver intfDriver = new IntfDriver();
		intfDriver.setDriverNric(workOrder.getDriverNric());
		intfDriver.setDriverTelephoneNo(workOrder.getDriverTelephoneNo());
		intfDriver.setDriverEmail(workOrder.getDriverEmail());
		
		intfDriver.setDateCreated(new Date());
		em.persist(intfDriver);
		
		
		if(workOrder.getTimeCheckIn()!=null && workOrder.getTimeCheckOut()!=null)
		{
			IntfTaxiDowntime intfTaxiDowntime = new IntfTaxiDowntime();
			intfTaxiDowntime.setDateCreated(new Date());
			intfTaxiDowntime.setVehicleId(workOrder.getVehicleId());
			intfTaxiDowntime.setStartTime(workOrder.getTimeCheckIn());
			intfTaxiDowntime.setEndTime(workOrder.getTimeCheckOut());
			
			em.persist(intfTaxiDowntime);
		}
		
		List<WorkOrderPart> workOrderParts = workOrder.getWorkOrderParts();
		
		if(workOrderParts!=null && workOrderParts.size()!=0)
		{
			for(int i=0;i<workOrderParts.size();i++)
			{
				WorkOrderPart workOrderPart = workOrderParts.get(i);
				AssetModel assetModel = workOrderPart.getAssetModel();

				String oldSerialNo = workOrderPart.getOldSerialNo();
				String newSerialNo = workOrderPart.getNewSerialNo();

				if(StringUtils.isNotEmpty(newSerialNo))
				{
					IntfPartReplacement intfPartReplacement = new IntfPartReplacement();
					intfPartReplacement.setAssetModelCode(assetModel.getAssetModelCode());
					intfPartReplacement.setDateCreated(new Date());
					intfPartReplacement.setNewSerialNo(newSerialNo);
					intfPartReplacement.setOldSerialNo(oldSerialNo);
					intfPartReplacement.setVehicleId(workOrder.getVehicleId());
						
					em.persist(intfPartReplacement);
				}
			}
		}
	}

	public void updateWorkOrderTecnician(WorkOrderTechnician workOrderTechnician) {

		Query query = em.createQuery("from WorkOrderTechnician where workOrder.workOrderId=:workOrderId and timeEnd is null");
		query.setParameter("workOrderId", workOrderTechnician.getWorkOrder().getWorkOrderId());
		List list = query.getResultList();
		if(list!=null)
		{
			for(int i=0;i<list.size();i++)
			{
				WorkOrderTechnician tmp = (WorkOrderTechnician) list.get(i);
				tmp.setTimeEnd(new Date());
				em.merge(tmp);
			}
		}



		workOrderTechnician.setTimeStart(new Date());
		em.persist(workOrderTechnician);

		query = em.createQuery("from WorkOrder where workOrderId=:workOrderId");
		query.setParameter("workOrderId", workOrderTechnician.getWorkOrder().getWorkOrderId());
		WorkOrder workOrder = (WorkOrder) query.getSingleResult();
		workOrder.setTechnician(workOrderTechnician.getTechnician());

		if(!workOrder.isWorkOrderStatusClosed())
			workOrder.setWorkOrderStatus(WorkOrder.WORKORDERSTATUS_INPROCESS);

		em.merge(workOrder);

	}
	
	
	public void updateWorkOrderTecnicianTime(WorkOrderTechnician workOrderTechnician) {

		WorkOrderTechnician newWorkOrderTechnician = em.find(WorkOrderTechnician.class, workOrderTechnician.getWorkOrderTechnicianId());

		newWorkOrderTechnician.setModifiedBy(workOrderTechnician.getModifiedBy());
		newWorkOrderTechnician.setDateModified(new Date());
		newWorkOrderTechnician.setTimeStart(workOrderTechnician.getTimeStart());
		newWorkOrderTechnician.setTimeEnd(workOrderTechnician.getTimeEnd());	
		em.merge(newWorkOrderTechnician);
		
		if(workOrderTechnician.isWoTimeUpdate())
		{
			WorkOrder newWorkOrder = em.find(WorkOrder.class, workOrderTechnician.getWorkOrder().getWorkOrderId());
		if(!newWorkOrder.isWorkOrderStatusClosed()){
				newWorkOrder.setModifiedBy(workOrderTechnician.getModifiedBy());
				newWorkOrder.setDateModified(new Date());
				newWorkOrder.setTimeCheckIn(workOrderTechnician.getTimeStart());
				newWorkOrder.setTimeCheckOut(workOrderTechnician.getTimeEnd());
				em.merge(newWorkOrder);
		}
		}		

	}

	public void updateClockInOut(WorkOrderTechnician workOrderTechnician) {

		Query query = em.createQuery("from WorkOrderTechnician where workOrder.workOrderId=:workOrderId and technician.userName=:userName and (timeEnd is null or timeStart is null)");
		query.setParameter("workOrderId", workOrderTechnician.getWorkOrder().getWorkOrderId());
		query.setParameter("userName", workOrderTechnician.getTechnician().getUserName());

		List list = query.getResultList();

		boolean completedOperation = false;
		if(list!=null && list.size()!=0)
		{
			WorkOrderTechnician workOrderTechnician2 = (WorkOrderTechnician) list.get(0);
			if(workOrderTechnician2.getTimeEnd()==null)
			{
				workOrderTechnician2.setTimeEnd(new Date());
				em.merge(workOrderTechnician2);
				completedOperation = true;
				
				workOrderTechnician.setTimeEnd(new Date());
				
			}
			else
			{
				workOrderTechnician2.setTimeStart(new Date());
				em.merge(workOrderTechnician2);	
			}
		}
		else
		{
			workOrderTechnician.setTimeStart(new Date());
			em.persist(workOrderTechnician);
		}

		query = em.createQuery("from WorkOrder where workOrderId=:workOrderId");
		query.setParameter("workOrderId", workOrderTechnician.getWorkOrder().getWorkOrderId());
		WorkOrder workOrder = (WorkOrder) query.getSingleResult();
		workOrder.setTechnician(workOrderTechnician.getTechnician());
		workOrderTechnician.setWorkOrder(workOrder);

		if(completedOperation)
		{
			workOrder.setTimeCheckOut(workOrderTechnician.getTimeEnd());
			workOrder.setWorkOrderStatus(WorkOrder.WORKORDERSTATUS_COMPLETED);
		}
		else
		{
			workOrder.setTimeCheckIn(workOrderTechnician.getTimeStart());
			workOrder.setWorkOrderStatus(WorkOrder.WORKORDERSTATUS_INPROCESS);
		}

		em.merge(workOrder);

	}

	private Location getLocationForNewSerialNo()
	{
		try
		{
			Query query = em.createQuery("from SystemCodeType where systemCodeTypeCode='"+GlobalConstant.SYSTEM_CODE_TYPE_WORKORDER_INVEHICLE_LOCATION+"'");
			SystemCodeType systemCodeType = (SystemCodeType) query.getSingleResult();
			query = em.createQuery("from Location where locationCode='"+systemCodeType.getSystemCodeTypeValue()+"'");
			Location location = (Location) query.getSingleResult();
			return location;
		}catch(NoResultException ex)
		{
			logger.error("Can't get location for new serial no ");
		}

		return null;
	}
	
	private Location getLocationForOldSerialNo()
	{
		try
		{
			Query query = em.createQuery("from SystemCodeType where systemCodeTypeCode='"+GlobalConstant.SYSTEM_CODE_TYPE_WORKORDER_FAULT_LOCATION+"'");
			SystemCodeType systemCodeType = (SystemCodeType) query.getSingleResult();
			query = em.createQuery("from Location where locationCode='"+systemCodeType.getSystemCodeTypeValue()+"'");
			Location location = (Location) query.getSingleResult();
			return location;
		}catch(NoResultException ex)
		{
			logger.error("Can't get location for old serial no ");
		}

		return null;
	}

	public List getCountWorkOrderWeek(Date startDate, Date endDate,Integer departmentId) {
		
		String addSql ="";
		
		if(departmentId!=null)
		{
			addSql=" and (accessDepartmentId is null or accessDepartmentId="+departmentId+")";
		}
		String sql = "select dateBooking,workOrderStatus,count(*) from AMTB_WORKORDER left join AMTB_DEPARTMENT on (departmentId=accessDepartmentId) where workOrderStatus is not null and dateBooking is not null and dateBooking between :startDate and :endDate "+addSql+" group by workOrderStatus, dateBooking";
		Query query = em.createNativeQuery(sql);
		query.setParameter("startDate", startDate);
		query.setParameter("endDate", endDate);
		return query.getResultList();
	}

	public List<WorkOrder> findWorkOrdersHistory(String taxiNo,String workOrderCode) {
		
		if(StringUtils.isEmpty(workOrderCode)) workOrderCode = "%";
		
		Query query = em.createQuery("from WorkOrder where workOrderCode != :workOrderCode and vehicleId=:vehicleId order by dateBooking desc");
		query.setParameter("workOrderCode", workOrderCode);
		query.setParameter("vehicleId", taxiNo);
		query.setMaxResults(5);
		
		List<WorkOrder> list = query.getResultList();
		
		return list;
	}


	public void cancelWorkOrder(WorkOrder workOrder) {
		
		WorkOrder currentWorkOrder  = em.find(WorkOrder.class, workOrder.getWorkOrderId());
		
		currentWorkOrder.setDateModified(new Date());
		
		currentWorkOrder.setModifiedBy(workOrder.getModifiedBy());
		
		currentWorkOrder.setWorkOrderStatus(WorkOrder.WORKORDERSTATUS_CANCEL);

		em.merge(currentWorkOrder);
	}
	
	private void createAssetTransactionfromPartChanges(WorkOrder workOrder,AssetEquipment assetEquipment,Location fromLocation,Location toLocation)
	{
		AssetTransaction assetTransaction = new AssetTransaction();
		assetTransaction.setAssetType(AssetModel.ASSETTYPE_EQUIPMENT);
		assetTransaction.setCreatedBy(workOrder.getCreatedBy());
		assetTransaction.setApprovedBy(workOrder.getCreatedBy());
		assetTransaction.setModifiedBy(workOrder.getCreatedBy());
		assetTransaction.setDateCreated(new Date());
		assetTransaction.setDateModified(new Date());
		assetTransaction.setApprovedDate(new Date());
		assetTransaction.setCompanyCode(workOrder.getCompanyCode());
		assetTransaction.setRemarks(workOrder.getWorkOrderCode());
		assetTransaction.setFromLocation(fromLocation);
		assetTransaction.setToLocation(toLocation);
		
		List<AssetTransactionItem> assetTransactionItems = new ArrayList<AssetTransactionItem>();
		
		AssetTransactionItem assetTransactionItem = new AssetTransactionItem();
		assetTransactionItem.setAssetModel(assetEquipment.getAssetEquipmentPK().getAssetModel());
		assetTransactionItem.setSerialNo(assetEquipment.getAssetEquipmentPK().getSerialNo());
		assetTransactionItem.setAssetPrice(0f);
		assetTransactionItems.add(assetTransactionItem);
		
		assetTransaction.setAssetTransactionItems(assetTransactionItems);
		
		assetTransactionService.createWorkOrderPartChanges(assetTransaction);
	}
	
	
}
